#include "fyp/app/DXUTWrapper.h"

//------------------------------------------------------------------------------
// additional header includes

#include "fyp/app/DxApp.h"

//------------------------------------------------------------------------------
namespace ming
{
namespace fyp
{
namespace app
{
	IDxApp *TDXUTWrapper::mApp = NULL;

	//--------------------------------------------------------------------------
	TDXUTWrapper::TDXUTWrapper()
	{
	}
	
	//--------------------------------------------------------------------------
	TDXUTWrapper::~TDXUTWrapper()
	{
	}

	//--------------------------------------------------------------------------
	void TDXUTWrapper::Run(IDxApp *app)
	{
		mApp = app;

		// init callbacks
		DXUTSetCallbackDeviceChanging(ModifyDeviceSettings, NULL);
		DXUTSetCallbackD3D9DeviceAcceptable(OnCheckDeviceAcceptable, NULL);
		DXUTSetCallbackD3D9DeviceCreated(OnDeviceCreated, NULL);
		DXUTSetCallbackD3D9DeviceReset(OnDeviceReset, NULL);
		DXUTSetCallbackD3D9FrameRender(OnFrameRender, NULL);
		DXUTSetCallbackD3D9DeviceLost(OnDeviceLost, NULL);
		DXUTSetCallbackD3D9DeviceDestroyed(OnDeviceDestroyed, NULL);
		DXUTSetCallbackMouse(OnMouseEvent, NULL);
		DXUTSetCallbackKeyboard(OnKeyboardEvent, NULL);
		DXUTSetCallbackMsgProc(OnWindowEvent, NULL);

		// init DXUT
		DXUTInit( false, true, NULL, false );

		// create window & run
		if(mApp)
		{
			tuple<const WCHAR*, bool, int, int> wndInfo = mApp->GetAppWndInfo();

			DXUTCreateWindow( get<0>(wndInfo) );
			DXUTCreateDevice( get<1>(wndInfo), get<2>(wndInfo), get<3>(wndInfo) );
		}
		else
		{
			DXUTCreateWindow( L"Soft Shadow Demo" );
			DXUTCreateDevice( true, 640, 480 );
		}

		DXUTMainLoop();
	}

	//--------------------------------------------------------------------------
	bool CALLBACK TDXUTWrapper::ModifyDeviceSettings(
		DXUTDeviceSettings* pDeviceSettings,
		void* pUserContext)
	{
		IDirect3D9 *d3dObj = DXUTGetD3D9Object();

		pDeviceSettings->d3d9.AdapterOrdinal = D3DADAPTER_DEFAULT;
		pDeviceSettings->d3d9.DeviceType = D3DDEVTYPE_HAL;
		pDeviceSettings->d3d9.pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
		pDeviceSettings->d3d9.pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

		for(UINT adapter=0; adapter < d3dObj->GetAdapterCount(); adapter++)
		{
			D3DADAPTER_IDENTIFIER9 identifier;
			d3dObj->GetAdapterIdentifier(adapter, 0, &identifier);
			
			if(strstr(identifier.Description, "NVPerfHUD") != 0)
			{
				pDeviceSettings->d3d9.AdapterOrdinal = adapter;
				pDeviceSettings->d3d9.DeviceType = D3DDEVTYPE_REF;
				break;
			}
		}

		return true;
	}

	//--------------------------------------------------------------------------
	bool CALLBACK TDXUTWrapper::OnCheckDeviceAcceptable(
		D3DCAPS9* pCaps,
		D3DFORMAT AdapterFormat,
		D3DFORMAT BackBufferFormat,
		bool bWindowed,
		void* pUserContext)
	{
		if(mApp) return mApp->AcceptDevice(pCaps, AdapterFormat, BackBufferFormat);

		return true;
	}
	
	//--------------------------------------------------------------------------
	HRESULT CALLBACK TDXUTWrapper::OnDeviceCreated(
		IDirect3DDevice9* pd3dDevice,
		const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
		void* pUserContext)
	{
		if(mApp) mApp->SetDevice(pd3dDevice);

		return S_OK;
	}

	//--------------------------------------------------------------------------
	HRESULT CALLBACK TDXUTWrapper::OnDeviceReset(
		IDirect3DDevice9* pd3dDevice,
		const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
		void* pUserContext)
	{
		if(mApp) mApp->RecreateResources(pd3dDevice, pBackBufferSurfaceDesc);

		return S_OK;
	}

	//--------------------------------------------------------------------------
	void CALLBACK TDXUTWrapper::OnFrameRender(
		IDirect3DDevice9* pd3dDevice,
		double fTime,
		float fElapsedTime,
		void* pUserContext)
	{
		if(mApp) mApp->Render(pd3dDevice, fElapsedTime);
	}

	//--------------------------------------------------------------------------
	void CALLBACK TDXUTWrapper::OnDeviceLost(
		void *pUserContext)
	{
	}

	//--------------------------------------------------------------------------
	void CALLBACK TDXUTWrapper::OnDeviceDestroyed(
		void *pUserContext)
	{
		if(mApp) mApp->DestroyResources();
		delete mApp;
	}

	//--------------------------------------------------------------------------
	void CALLBACK TDXUTWrapper::OnMouseEvent(
		bool bLeftButtonDown,
		bool bRightButtonDown,
		bool bMiddleButtonDown,
		bool bSideButton1Down,
		bool bSideButton2Down,
		int nMouseWheelDelta,
		int xPos,
		int yPos,
		void* pUserContext)
	{
		if(mApp) mApp->HandleMouseEvent(
			bLeftButtonDown,
			bRightButtonDown,
			bMiddleButtonDown,
			nMouseWheelDelta,
			xPos,
			yPos);
	}

	//--------------------------------------------------------------------------
	void CALLBACK TDXUTWrapper::OnKeyboardEvent(
		UINT nChar,
		bool bKeyDown,
		bool bAltDown,
		void* pUserContext)
	{
		if(mApp) mApp->HandleKeyboardEvent(
			nChar,
			bKeyDown,
			bAltDown);
	}

	//--------------------------------------------------------------------------
	LRESULT CALLBACK TDXUTWrapper::OnWindowEvent(
		HWND hWnd,
		UINT uMsg,
		WPARAM wParam,
		LPARAM lParam,
		bool* pbNoFurtherProcessing,
		void* pUserContext)
	{
		if(mApp) mApp->HandleWindowEvent(
			hWnd,
			uMsg,
			wParam,
			lParam,
			pbNoFurtherProcessing);

		return 0;
	}
	
	//--------------------------------------------------------------------------
}
}
}
